using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using System;

namespace IQIGame.Onigao.GamePlay
{
    /// <summary>
    /// 提示实体窗口基类
    /// 该类型可处理异步调用
    /// 
    /// 使用前仔细阅读每个接口的注释
    /// </summary>
    public abstract class BaseNoticeEntityUI : UIEntityWindow
    {
        private AutoResetUniTaskCompletionSource<NoticeResultType> _completeTaskSource;

        /// <summary>
        /// 统一的显示提示，开启任务的接口
        /// 调用前最好判断一下当前的window.isActive是不是true，如果不是返回NoticeResultType.Close
        /// 因为UI在某些奇葩写法下可能在OnShow还没有执行完以前被关闭，概率很低
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public abstract UniTask<NoticeResultType> PopWindow(UIBaseData data);

        /// <summary>
        /// 所有任务正常处理完的方法，比如玩家点击了确认或取消按钮
        /// 具体是Close还是干别的事自己决定
        /// </summary>
        protected abstract void OnNoticeComplete();

        /// <summary>
        /// 开始任务的按钮，在PopWindow的最后调用，并await
        /// </summary>
        /// <returns></returns>
        protected async UniTask<NoticeResultType> CreateAndAwaitTask()
        {
            _completeTaskSource = AutoResetUniTaskCompletionSource<NoticeResultType>.Create();

            NoticeResultType result = default;
            try
            {
                result = await _completeTaskSource.Task;
                OnNoticeComplete();
            }
            catch (OperationCanceledException)
            {
                result = NoticeResultType.CancelBySystem;
            }
            catch (Exception e)
            {
                LogGame.LogException(e);
                result = NoticeResultType.Exception;
            }

            return result;
        }

        /// <summary>
        /// 正常完成任务的接口，比如玩家手动点击确认，取消，关闭
        /// </summary>
        /// <param name="type"></param>
        protected void CallTaskComplete(NoticeResultType type)
        {
            if (_completeTaskSource != null)
            {
                // 注意！这里要先置空，再调用，TrySetResult会先调用await之后的代码，如果await之后有给TaskSource赋新值，然后这里再置空，那么_completeActTaskSource就永远为null了
                var ts = _completeTaskSource;
                _completeTaskSource = null;
                ts.TrySetResult(type);
            }
        }

        /// <summary>
        /// 处理意外关闭，如果是玩家手动关闭，此时_completeTaskSource == null，逻辑不执行
        /// 子类一定要重写该方法，并调用base.OnHide
        /// </summary>
        protected override void OnHide()
        {
            if (_completeTaskSource != null)
            {
                var ts = _completeTaskSource;
                _completeTaskSource = null;
                ts.TrySetCanceled();
            }
        }
    }
}
